package com.leonzhangxf.spel.evaluation;

import com.leonzhangxf.spel.bean.Inventor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;

import java.util.*;

/**
 * A simple demo for primary use independently of SpEL.
 *
 * @author leonzhangxf
 * @date 20190425
 */
public class SimpleDemo {

    public static void main(String[] args) {
        primary();
        System.out.println("============================primary1");
        primary1();
        System.out.println("============================primary2");
        primary2();
        System.out.println("============================primary3");
        primary3();
        System.out.println("============================primary4");
        primary4();
        System.out.println("============================primary5");
        primary5();
        System.out.println("============================primary6");
        primary6();
        System.out.println("============================primary7");
        primary7();
    }

    private static void primary() {
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression("'Hello World'");
        System.out.println(expression.getValue(String.class));
    }

    private static void primary1() {
        ExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression("'Hello World'.concat(' Leon')");
        System.out.println(exp.getValue(String.class));
    }

    private static void primary2() {
        ExpressionParser parser = new SpelExpressionParser();
        // invokes 'getBytes()'
        Expression exp = parser.parseExpression("'Hello World'.bytes");
        System.out.println(Arrays.toString(exp.getValue(byte[].class)));
    }

    private static void primary3() {
        ExpressionParser parser = new SpelExpressionParser();
        // invokes 'getBytes().length'
        Expression exp = parser.parseExpression("'Hello World'.bytes.length");
        System.out.println(exp.getValue(int.class));
    }

    private static void primary4() {
        ExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression("new String('hello world').toUpperCase()");
        System.out.println(exp.getValue(String.class));
    }

    private static void primary5() {
        // Create and set a calendar
        GregorianCalendar c = new GregorianCalendar();
        c.set(1856, Calendar.JULY, 9);

        // The constructor arguments are name, birthday, and nationality.
        Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");

        ExpressionParser parser = new SpelExpressionParser();

        Expression exp = parser.parseExpression("name");
        String name = exp.getValue(tesla, String.class);
        System.out.println(name);
        // name == "Nikola Tesla"

        exp = parser.parseExpression("name == 'Nikola Tesla'");
        System.out.println(exp.getValue(tesla, boolean.class));
        // result == true
    }

    /**
     * Type Conversion
     */
    private static void primary6() {
        Simple simple = new Simple();
        simple.booleanList.add(true);

        EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
        ExpressionParser parser = new SpelExpressionParser();

        // "false" is passed in here as a String. SpEL and the conversion service
        // will recognize that it needs to be a Boolean and convert it accordingly.
        parser.parseExpression("booleanList[0]").setValue(context, simple, "false");

        // b is false
        System.out.println(simple.booleanList.get(0));

        try {
            parser.parseExpression("booleanList[1]").setValue(simple, "true");
            System.out.println(simple.booleanList);
        } catch (Exception ex) {
            // 这里会报错，因为默认的Context配置无法保证在集合的基础上增大Size。
            System.out.println(ex.getMessage());
        }
    }

    /**
     * Parser Configuration
     */
    private static void primary7() {
        // Turn on:
        // - auto null reference initialization
        // - auto collection growing
        SpelParserConfiguration config = new SpelParserConfiguration(true,true);

        ExpressionParser parser = new SpelExpressionParser(config);

        Expression expression = parser.parseExpression("list[3]");

        Demo demo = new Demo();

        // demo.list will now be a real collection of 4 entries
        // Each entry is a new empty String
        Object value = expression.getValue(demo);
        System.out.println("".equals(value));

        Expression expression1 = parser.parseExpression("list[1]");
        expression1.setValue(demo, "LOL");
        System.out.println(demo.list);
    }

    public static class Simple {
        public List<Boolean> booleanList = new ArrayList<>();
    }

    public static class Demo {
        public List<String> list = new ArrayList<>();
    }

}
